package body Liste_Commandes is

    procedure Ajouter (Liste_Comm : in out T_Liste; Comm : in Commande) is
    begin
        Liste.Ajout_Tete(Liste_Comm, Comm);
    end Ajouter;

    procedure Trier (Liste_Comm : in out T_Liste) is        
        procedure Tri_Liste_Commandes is new Liste.Tri (Comparer);
    begin
        Tri_Liste_Commandes(Liste_Comm);
    end Trier;

    procedure Trier_Par_Client (Liste_Comm : in out T_Liste) is
       function Comparer_Clients (A,B : Commandes.Commande) return Boolean is
       begin
          return Commandes.Get_Client(A)>Commandes.Get_Client(B);
       end Comparer_Clients ;
       procedure Tri_Commandes is new Liste.Tri (Comparer_Clients);
    begin
       Tri_Commandes(Liste_Comm);
    end Trier_Par_Client ;
		
    procedure Sousliste_Attente (Liste_Comm, Liste_Comm_Attente : in out T_Liste) is
        procedure Sousliste_Att is new Liste.Sousliste (Commandes.En_Attente);
    begin
        Sousliste_Att(Liste_Comm, Liste_Comm_Attente);
    end Sousliste_Attente;

    procedure Sousliste_Erronees (Liste_Comm, Liste_Comm_Err : in out T_Liste) is
        procedure Sousliste_Err is new Liste.Sousliste (Commandes.Erronee);
    begin
        Sousliste_Err(Liste_Comm, Liste_Comm_Err);
    end Sousliste_Erronees;
    
    procedure Tasser_Colonne (
        Liste_Comm : in out T_Liste;
        Liste_Pl : in out Liste_Plaques.T_Liste;
        Comm_Supprimee : in Commandes.Commande) is
        
        use Emplacements; use Pieces; use Commandes;
        
        Piece_Supprimee : Ptr_Piece := Get_Piece_Assoc(Comm_Supprimee);

        Position_Piece_Supprimee : Natural :=
            Get_Hauteur(Get_Position(Get_Emplacement(Get_Piece_Assoc(Comm_Supprimee))));
        Colonne_Piece_Supprimee : Natural :=
            Get_Largeur(Get_Position(Get_Emplacement(Get_Piece_Assoc(Comm_Supprimee))));
        Id_Plaque_Piece_Supprimee : Natural :=
            Get_Id_Plaque(Get_Emplacement(Get_Piece_Assoc(Comm_Supprimee)));
        Hauteur_Piece_Supprimee : Natural :=
            Get_Hauteur(Get_Dimension(Get_Piece_Assoc(Comm_Supprimee)));
        Largeur_Piece_Supprimee : Natural :=
            Get_Largeur(Get_Dimension(Get_Piece_Assoc(Comm_Supprimee)));

        Premiere_Piece : Ptr_Piece := Null; -- Premiere piece de la colonne            
        Derniere_Piece : Ptr_Piece := Null; -- Derniere piece de la colonne
        Deplacement_Gauche : Natural;
        
        procedure Tasser_Haut (Comm : in out Commandes.Commande) is
            
            Position_Piece_Analysee : Natural;
            Colonne_Piece_Analysee : Natural;
            Id_Plaque_Piece_Analysee : Natural;        

            Piece_Deplacee : Ptr_Piece := Get_Piece_Assoc(Comm);
            
            Nouvel_Empl : Emplacement;
        begin
            if Piece_Deplacee /= Null then
        
                Position_Piece_Analysee := Get_Hauteur(Get_Position(Get_Emplacement(Piece_Deplacee.all)));
                Colonne_Piece_Analysee := Get_Largeur(Get_Position(Get_Emplacement(Piece_Deplacee.all)));
                Id_Plaque_Piece_Analysee := Get_Id_Plaque(Get_Emplacement(Piece_Deplacee.all));    
                
                if (Id_Plaque_Piece_Supprimee = Id_Plaque_Piece_Analysee)
                    and (Colonne_Piece_Analysee = Colonne_Piece_Supprimee) then

                    if (Position_Piece_Analysee > Position_Piece_Supprimee) then
                        -- La piece analysee se trouve au dessous de la piece supprimee, il faut tasser en haut
                        Nouvel_Empl := Get_Emplacement(Piece_Deplacee.all);
                        Deplacer(Nouvel_Empl, 0, -Hauteur_Piece_Supprimee);
                        Pieces.Set_Emplacement(Piece_Deplacee.all, Nouvel_Empl);
                        
                        if Get_Hauteur(Get_Position(Nouvel_Empl)) = 0 then
                            Premiere_Piece := Piece_Deplacee;
                        end if;
                    end if;
                    
                    if (Derniere_Piece = Null) or else 
                        (Position_Piece_Analysee > Get_Hauteur(Get_Position(Get_Emplacement(Derniere_Piece.all)))) then
                        Derniere_Piece := Piece_Deplacee;
                    end if;
                end if;
                
            end if;
        end Tasser_Haut;
        
        procedure Tasser_Toutes_Haut is new Liste.Map(Tasser_Haut);
        
        procedure Tasser_Gauche (Comm : in out Commandes.Commande) is
            Colonne_Piece_Analysee : Natural;
            Id_Plaque_Piece_Analysee : Natural;        

            Piece_Deplacee : Ptr_Piece := Get_Piece_Assoc(Comm);
            
            Nouvel_Empl : Emplacement;
        begin
            if Piece_Deplacee /= Null then
                Colonne_Piece_Analysee := Get_Largeur(Get_Position(Get_Emplacement(Piece_Deplacee.all)));
                Id_Plaque_Piece_Analysee := Get_Id_Plaque(Get_Emplacement(Piece_Deplacee.all));
                
                if (Id_Plaque_Piece_Supprimee = Id_Plaque_Piece_Analysee)
                    and (Colonne_Piece_Analysee > Colonne_Piece_Supprimee) then
                    
                    -- La piece analysee se trouve a droite de la piece supprimee, il faut tasser a gauche
                    Nouvel_Empl := Get_Emplacement(Piece_Deplacee.all);       
                    Deplacer(Nouvel_Empl, -Deplacement_Gauche,0);
                    Pieces.Set_Emplacement(Piece_Deplacee.all, Nouvel_Empl);
                end if;
            end if;
        end Tasser_Gauche;
        
        procedure Tasser_Toutes_Gauche is new Liste.Map(Tasser_Gauche);
      
    begin
        Tasser_Toutes_Haut(Liste_Comm);
        
        if (Premiere_Piece = Null) and (Derniere_Piece /= Null) then
            -- La premiere piece n'a pas changee de position
            Deplacement_Gauche := 0;
        elsif (Premiere_Piece = Null) and (Derniere_Piece = Null) then
            -- On a supprimee la derniere piece de la colonne
            Deplacement_Gauche := Largeur_Piece_Supprimee;
        else
            Deplacement_Gauche := Largeur_Piece_Supprimee - Get_Largeur(Get_Dimension(Premiere_Piece.all));
        end if;
        
        
        if Derniere_Piece /= Null then
            -- Colonne = Position en X sur la plaque
            Liste_Plaques.Redim_Morceau_Vide_Colonne(
                Liste_Pl => Liste_Pl,
                Id_Plaque => Get_Id_Plaque(Get_Emplacement(Piece_Supprimee.all)),
                Colonne => Get_Largeur(Get_Position(Get_Emplacement(Piece_Supprimee.all))),
                Largeur => Get_Largeur(Get_Dimension(Derniere_Piece.all)),
                Hauteur => Get_Hauteur(Get_Dimension(Piece_Supprimee.all)),
                Decalage_Gauche => Deplacement_Gauche
                );
            
        else
            Liste_Plaques.Redim_Morceau_Vide_Colonne(
                Liste_Pl => Liste_Pl,
                Id_Plaque => Get_Id_Plaque(Get_Emplacement(Piece_Supprimee.all)),
                Colonne => Get_Largeur(Get_Position(Get_Emplacement(Piece_Supprimee.all))),
                Largeur => 0,
                Hauteur => 0,
                Decalage_Gauche => Deplacement_Gauche
                );
                
                
            -- Il ne reste aucune piece dans la colonne
        end if;
        
        if (Premiere_Piece /= Null) or (Derniere_Piece = Null) then
            -- la premiere piece a ete modifiee...
            Tasser_Toutes_Gauche(Liste_Comm);
        end if;
        
        --Ada.Text_Io.Put("Dimensions derniere piece : " & ToString(Get_Dimension(Derniere_Piece.all)));
             
    end Tasser_Colonne;
    
    procedure Annuler (
        Liste_Comm : in out T_Liste; 
        Liste_Pl : in out Liste_Plaques.T_Liste;
        Id_Comm : in Natural;
        Comm_Supprimee : out Commandes.Commande
        ) is
        
        function Comparer (Comm : Commandes.Commande) return Boolean is
        begin
            return Commandes.Get_Id(Comm) = Id_Comm;
        end Comparer;
        
        procedure Supprime_Commande is new Liste.Supprime(Comparer);
    begin
        Supprime_Commande(Liste_Comm, Comm_Supprimee);
        if Get_Etat(Comm_Supprimee) = 'S' then
            -- Si la piece a deja ete placee, on tasse vers le haut
            Tasser_Colonne(Liste_Comm, Liste_Pl, Comm_Supprimee);
        end if;
    end Annuler;
    
    procedure Calculer_Indicateurs (
        Liste_Comm : in out T_Liste;
        Indicateurs : out Statistiques.Stat
        ) is
    
        procedure Analyser_Commande (Comm : in Commandes.Commande) is
        begin
            case Commandes.Get_Etat(Comm) is
                when 'A' => Statistiques.Incr_Commandes_Attente(Indicateurs, Pieces.Get_Categorie(Commandes.Get_Piece_Assoc(Comm)).all);
                when 'S' => Statistiques.Incr_Commandes_Satisfaites(Indicateurs, Pieces.Get_Categorie(Commandes.Get_Piece_Assoc(Comm)).all);
                when others => Statistiques.Incr_Commandes_Erronees(Indicateurs);
            end case;
        end Analyser_Commande;
        
        procedure Analyser is new Liste.Foreach(Analyser_Commande);
    begin
        Statistiques.Init(Indicateurs);
        Analyser(Liste_Comm);
    end Calculer_Indicateurs;
    
    function Copie (L1 : T_Liste) return T_Liste is
        L2 : T_Liste := Liste.Cree_SListe;
        
        procedure Dupliquer (C : in Commande) is
        begin
            Liste.Ajout_Fin(L2, Copie(C));
        end Dupliquer;
        
        procedure Dupliquer_Tout is new Liste.Foreach (Dupliquer);
    begin
        Dupliquer_Tout(L1);
        return L2;
    end Copie;
    
	procedure Afficher (Liste_Comm : in out T_Liste) is
		procedure Afficher_Commande (C : in out Commande) is
		begin
			Ada.Text_Io.Put_Line(Commandes.ToString(C));
		end Afficher_Commande;
		
		procedure Afficher_Tout is new Liste.Map(Afficher_Commande);
	begin
		Afficher_Tout(Liste_Comm);
	end Afficher;
	
end Liste_Commandes;